﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace WizzardTheGame
{
    abstract class Character: IDrawable
    {
        protected const float GRAVITY = 0.2f;
        protected const int MAX_GRAVITY = -3;
        private const Int32 DEFAULT_HP = 100;
        private const Int32 DEFAULT_EXP = 50;
        private const Int32 DEFAULT_ATTACK = 10;
        private const float DEFAULT_SPEED = 0.5f;
        protected static Vector3 LeftVec = new Vector3(1f, 0f, 0f);
        protected static Vector3 RightVec = new Vector3(-1f, 0f, 0f);
        private Object3D charModel;
        private int maxHP;
        private int currentHP;
        private int attackPower;
        private int defense;
        private float speed;
        private Inventory inventory;
        private int experience;
        private int gold;
        private Vector3 velocity;
        private Vector3 position;
        private Vector3 moveVector;
        private bool isAlive;

        #region Properties

        public Object3D CharModel
        {
            get { return charModel; }
            set { charModel = value; }
        }

        public Vector3 MoveVector
        {
            get { return moveVector; }
            set { moveVector = value; }
        }

        public int MaxHP
        {
            get { return maxHP; }
            set { maxHP = value; }
        }

        public Inventory Inventory
        {
            get { return inventory; }
            set { inventory = value; }
        }

        public virtual int CurrentHP
        {
            get { return currentHP; }
            set { currentHP = value; }
        }

        public float Speed
        {
            get { return speed; }
            set { speed = value; }
        }

        public int AttackPower
        {
            get { return attackPower; }
            set { attackPower = value; }
        }

        public int Defense
        {
            get { return defense; }
            set { defense = value; }
        }

        public virtual int Experience
        {
            get { return experience; }
            set { experience = value; }
        }

        public int Gold
        {
            get { return gold; }
            set { gold = value; }
        }

        public Vector3 Velocity
        {
            get { return velocity; }
            set
            {
                velocity = value;
                CharModel.Velocity = value;
            }
        }

        public virtual Vector3 Position
        {
            get { return position; }
            set 
            { 
                position = value;
                CharModel.Position = value;
            }
        }

        public bool IsAlive
        {
            get { return isAlive; }
            set { isAlive = value; }
        }
        #endregion

        protected Character(string path):this()
        {
            CharModel = new Object3D(path);
        }

        protected Character()
        {
            if(CharModel == null) CharModel = new Object3D();
            MaxHP = DEFAULT_HP;
            currentHP = DEFAULT_HP;
            experience = DEFAULT_EXP;
            AttackPower = DEFAULT_ATTACK;
            Speed = DEFAULT_SPEED;
            Gold = 0;
            Velocity = Vector3.Zero;
            Position = Vector3.Zero;
            IsAlive = true;
            Inventory = new Inventory();
        }

        public virtual void Update()
        {
            if (IsAlive)
            {
                ApplyGravity();
                ApplyMove();
            }
        }
        protected abstract void Attack();

        //protected virtual void ApplyGravity()
        //{
        //    int i = 0;
        //    bool collision = false;
        //    List<GameEnvironment> gameEnvs = GameWorld.getInstance().GameEnvironment;
        //    while (!collision && i < gameEnvs.Count)
        //    {
        //        collision = gameEnvs[i].EnvModel.TestCollision(CharModel);
        //        i++;
        //    }
        //    Vector3 gravity = Velocity;
        //    if (!collision)
        //    {
        //        if (!(Velocity.Y < MAX_GRAVITY))
        //        {
        //            //Apply gravity
        //            gravity.Y -= GRAVITY;
        //            Velocity = gravity;
        //        }
        //    }
        //    else
        //    {
        //        gravity.Y = 0f;
        //    }
        //    Velocity = gravity;
        //}

        protected virtual void ApplyGravity()
        {
            if (!(Velocity.Y < MAX_GRAVITY))
            {
                //Apply gravity
                Vector3 vel = Velocity;
                vel.Y -= GRAVITY;
                Velocity = vel;
            }
            Position += Velocity;
            int i = 0;
            bool collision = false;
            List<GameEnvironment> gameEnvs = GameWorld.getInstance().GameEnvironment;
            while (!collision && i < gameEnvs.Count)
            {
                collision = gameEnvs[i].EnvModel.TestCollision(CharModel);
                i++;
            }
            if (collision)
            {
                Position -= Velocity;
                Vector3 vel = Velocity;
                vel.Y = 0;
                Velocity = vel;
            }
        }

        protected virtual void ApplyMove()
        {
            //Move
            int i = 0;
            bool collision = false;
            List<GameEnvironment> gameEnvs = GameWorld.getInstance().GameEnvironment;
            Position += MoveVector;
            collision = false;
            i = 0;
            while (!collision && i < gameEnvs.Count)
            {
                collision = gameEnvs[i].EnvModel.TestCollision(CharModel);
                i++;
            }
            if (collision) Position -= MoveVector;
        }

        #region IDrawable Members

        public virtual void Draw()
        {
            if (IsAlive)
            {
                CharModel.Draw();
            }
        }

        #endregion
    }
}
